﻿namespace CRM2011InternalEmail.Workflow
{
    using Entities;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using Microsoft.Xrm.Sdk.Workflow;
    using System;
    using System.Activities;
    using System.ServiceModel;
    using System.Text;

    public sealed class DeleteAttachment : CodeActivity
    {
        /// <summary>
        /// Executes the workflow activity.
        /// </summary>
        /// <param name="executionContext">The execution context.</param>
        protected override void Execute(CodeActivityContext executionContext)
        {
            // Create the tracing service
            ITracingService tracingService = executionContext.GetExtension<ITracingService>();

            if (tracingService == null)
            {
                throw new InvalidPluginExecutionException("Failed to retrieve tracing service.");
            }

            tracingService.Trace("Entered DeleteAttachment.Execute(), Activity Instance Id: {0}, Workflow Instance Id: {1}",
                executionContext.ActivityInstanceId, executionContext.WorkflowInstanceId);

            // Create the context
            IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
            
            if (context == null)
            {
                throw new InvalidPluginExecutionException("Failed to retrieve workflow context.");
            }

            tracingService.Trace("DeleteAttachment.Execute(), Correlation Id: {0}, Initiating User: {1}",
                context.CorrelationId, context.InitiatingUserId);

            IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            try
            {
                EntityCollection attachments = GetAttachments(service, EmailWithAttachments.Get(executionContext).Id);
                
                int? deleteSize = DeleteSize.Get(executionContext);
                if (deleteSize == null)
                    deleteSize = int.MaxValue;

                bool appendNotice = AppendNotice.Get(executionContext);
                StringBuilder notice = new StringBuilder();

                foreach (ActivityMimeAttachment a in attachments.Entities)
                {
                    if (a.FileSize >= deleteSize)
                    {
                        DeleteEmailAttachment(service, a.Id);

                        if (appendNotice)
                            notice.AppendLine("Deleted Attachment: " + a.FileName + " " + DateTime.Now.ToShortDateString() + "\r\n");
                    }
                }

                if (appendNotice && notice.Length > 0)
                    UpdateEmail(service, EmailWithAttachments.Get(executionContext).Id, notice.ToString());
            }
            catch (FaultException<OrganizationServiceFault> e)
            {
                tracingService.Trace("Exception: {0}", e.ToString());
                throw;
            }

            tracingService.Trace("Exiting DeleteAttachment.Execute(), Correlation Id: {0}", context.CorrelationId);
        }

        private void UpdateEmail(IOrganizationService service, Guid id, string notice)
        {
            Annotation note = new Annotation();
            note.NoteText = notice;
            note.ObjectId = new EntityReference(Email.EntityLogicalName, id);
            service.Create(note);
            
        }

        private EntityCollection GetAttachments(IOrganizationService service, Guid id)
        {
            //Query for the attachments
            QueryExpression query = new QueryExpression()
            {
                EntityName = ActivityMimeAttachment.EntityLogicalName,
                ColumnSet = new ColumnSet("filesize", "filename"),
                Criteria = new FilterExpression
                {
                    Conditions = 
                    {
                        new ConditionExpression
                        {
                            AttributeName = "objectid",
                            Operator = ConditionOperator.Equal,
                            Values = { id }
                        }
                    }
                }
            };

            return service.RetrieveMultiple(query);
        }

        private void DeleteEmailAttachment(IOrganizationService service, Guid id)
        {
            service.Delete(ActivityMimeAttachment.EntityLogicalName, id);
        }

        [RequiredArgument]
        [Input("Email With Attachments To Remove")]
        [ReferenceTarget("email")]
        public InArgument<EntityReference> EmailWithAttachments { get; set; }

        [RequiredArgument]
        [Input("Delete >= Than X KB")]
        public InArgument<int> DeleteSize { get; set; }

        [RequiredArgument]
        [Input("Add Delete Notice As Note?")]
        public InArgument<bool> AppendNotice { get; set; }
    }
}